Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\dynamic\src\proto\message_ext.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use std::ops::Deref;
30
use std::rc::Rc;
31
use bp3d_protoc::compiler::message::{Field, FieldType, Message, Referenced};
32
use crate::buffer::Builder;
33
use crate::component::ComponentType;
34
use crate::component::factory::{ContainerOptions, Factory, Key};
35
use crate::field::option::Optional;
36
use crate::field::primitive::from_fixed_field_type;
37
use crate::proto::struct_ext::new_structure_internal;
38
39
pub struct MessageExt {
40
    pub(crate) message: Rc<Message>,
41
    pub(crate) factory: Rc<Factory>
42
}
43
44
impl Deref for MessageExt {
45
    type Target = Rc<Message>;
46
47
0
    fn deref(&self) -> &Self::Target {
48
0
        &self.message
49
0
    }
50
}
51
52
12
fn new_field_internal(factory: &Rc<Factory>, builder: Builder<'static>, field: &Field) -> crate::component::factory::Result<Builder<'static>> {
53
12
    match &field.ty {
54
6
        FieldType::Fixed(v) => Ok(builder.size(v.ty.get_byte_size()).primitive(from_fixed_field_type(v.ty, field.endianness))),
55
2
        FieldType::Ref(v) => {
56
2
            match v {
57
0
                Referenced::Struct(v1) => Ok(new_structure_internal(Builder::new(&field.name), &*v1)),
58
2
                Referenced::Message(v1) => new_message_internal(factory, Builder::new(&field.name), &*v1)
59
            }
60
        }
61
4
        FieldType::Buffer => factory.with_component(Key::for_buffer(field.codec.as_ref().unwrap(), None), |comp| comp.build(Builder::new(&field.name))),
62
0
        FieldType::SizedBuffer(v) => factory.with_component(Key::for_buffer(field.codec.as_ref().unwrap(), Some((v.ty, field.endianness).into())), |comp| comp.build(Builder::new(&field.name))),
63
0
        FieldType::FixedContainer(v) => {
64
0
            let options = ContainerOptions {
65
0
                inner_ty: v.item_type.clone(),
66
0
                count_ty: (v.ty, field.endianness).into(),
67
0
                size_ty: None,
68
0
            };
69
0
            factory.with_component(Key::for_container(field.codec.as_ref().unwrap(), options), |comp| comp.build(Builder::new(&field.name)))
70
        }
71
0
        FieldType::Container(v) => {
72
0
            let options = ContainerOptions {
73
0
                inner_ty: Rc::new(MessageExt { factory: factory.clone(), message: v.item_type.clone() }),
74
0
                count_ty: (v.ty, field.endianness).into(),
75
0
                size_ty: None,
76
0
            };
77
0
            factory.with_component(Key::for_container(field.codec.as_ref().unwrap(), options), |comp| comp.build(Builder::new(&field.name)))
78
        }
79
0
        FieldType::SizedContainer(v) => {
80
0
            let options = ContainerOptions {
81
0
                inner_ty: Rc::new(MessageExt { factory: factory.clone(), message: v.item_type.clone() }),
82
0
                count_ty: (v.ty, field.endianness).into(),
83
0
                size_ty: Some((v.size_ty, field.endianness).into()),
84
0
            };
85
0
            factory.with_component(Key::for_container(field.codec.as_ref().unwrap(), options), |comp| comp.build(Builder::new(&field.name)))
86
        }
87
        FieldType::Union(_) => {
88
0
            panic!("Union types are currently not supported");
89
        }
90
        FieldType::Payload => {
91
0
            panic!("Payload types are currently not supported");
92
        }
93
    }
94
12
}
95
96
#[derive(Clone)]
97
struct FieldType1 {
98
    field: Field,
99
    factory: Rc<Factory>
100
}
101
102
impl ComponentType for FieldType1 {
103
2
    fn name(&self) -> &str {
104
2
        &self.field.name
105
2
    }
106
107
2
    fn build(&self, builder: Builder<'static>) -> Builder<'static> {
108
        //TODO: Better error handling
109
2
        new_field_internal(&self.factory, builder, &self.field).unwrap()
110
2
    }
111
}
112
113
4
fn new_message_internal(factory: &Rc<Factory>, mut builder: Builder<'static>, value: &Message) -> crate::component::factory::Result<Builder<'static>> {
114
16
    for 
field12
in &value.fields {
115
12
        if field.optional {
  Branch (115:12): [Folded - Ignored]
  Branch (115:12): [True: 2, False: 10]
116
2
            let ft = FieldType1 {
117
2
                field: field.clone(),
118
2
                factory: factory.clone()
119
2
            };
120
2
            let opt = Optional(ft);
121
2
            builder = builder.add_child(Builder::new(&field.name).component(opt));
122
2
            continue;
123
10
        }
124
10
        builder = builder.add_child(new_field_internal(factory, Builder::new(&field.name), field)
?0
);
125
    }
126
4
    Ok(builder)
127
4
}
128
129
impl ComponentType for MessageExt {
130
2
    fn name(&self) -> &str {
131
2
        &self.message.name
132
2
    }
133
134
0
    fn key(&self) -> usize {
135
0
        Rc::as_ptr(&self.message) as _
136
0
    }
137
138
2
    fn build(&self, builder: Builder<'static>) -> Builder<'static> {
139
        //TODO: Better error handling
140
2
        new_message_internal(&self.factory, builder, &self.message).unwrap()
141
2
    }
142
}